/* vim: set sw=8 ts=8 sts=8 expandtab: */
#ifndef CMAID_MAGIC_H
#define CMAID_MAGIC_H

#define CMAID_MAGIC_CONTAINER       0xDF000097
#define CMAID_MAGIC_CONTAINER_MASK  0xFF0000FF
#define CMAID_MAGIC_LIST           (0x00ECCE00 | CMAID_MAGIC_CONTAINER)
#define CMAID_MAGIC_SET            (0x00DBBD00 | CMAID_MAGIC_CONTAINER)
#define CMAID_MAGIC_MAP            (0x00CAAC00 | CMAID_MAGIC_CONTAINER)
#define CMAID_MAGIC_CACHE          (0x00A88A00 | CMAID_MAGIC_CONTAINER)

#ifndef CMAID_DEBUG
# define CMAID_CHECK_POINTER_RET(par, ret) (void)par
# define CMAID_CHECK_POINTER(par) (void)par
# define CMAID_CHECK_CONTAINER_RET(c, ret) (void)c
# define CMAID_CHECK_CONTAINER(c) (void)c
# define CMAID_CHECK_TYPE_RET(c, type, ret) (void)c
# define CMAID_CHECK_TYPE(c, type) (void)c
# define __CMAID_CHECKED_ITER__
#else
# include <stdio.h> /* for fprintf */
# define CMAID_CHECK_POINTER(par) CMAID_CHECK_POINTER_RET(par, )
# define CMAID_CHECK_POINTER_RET(par, ret) \
        do { \
                if (!(par)) \
                { \
                        cmaid_magic_warning_print(NULL, __func__, #par); \
                        return ret; \
                } \
        } while (0)
# define CMAID_CHECK_CONTAINER(c) CMAID_CHECK_CONTAINER_RET(c, )
# define CMAID_CHECK_CONTAINER_RET(c, ret) \
        do { \
                if (!(c) \
                        || ((((Cmaid_Container_Interface *)c->interface)->magic \
                                        & CMAID_MAGIC_CONTAINER_MASK) \
                                != CMAID_MAGIC_CONTAINER))\
                { \
                        cmaid_magic_warning_print("container", __func__, #c); \
                        return ret; \
                } \
        } while (0)

# define CMAID_CHECK_TYPE(c, type) CMAID_CHECK_TYPE_RET(c, type, )
# define CMAID_CHECK_TYPE_RET(c, type, ret) \
        do { \
                if (!(c) \
                        || (((Cmaid_Container_Interface *)c->interface)->magic \
                                != type))\
                { \
                        cmaid_magic_warning_print(#type, __func__, #c); \
                        return ret; \
                } \
        } while (0)

# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
#  define __CMAID_CHECKED_ITER__         __attribute__(\
                                        (__cleanup__(cmaid_magic_iter_check)))\
                                        = {NULL}
# else
#  define __CMAID_CHECKED_ITER__
#endif
#endif

EAPI void cmaid_magic_iter_check(Cmaid_Iter *iter);
EAPI void cmaid_magic_warning_print(const char *type, const char *func,
                                        const char *param);

#endif /* CMAID_MAGIC_H */
